"""
RAGFlow MCP处理器模块

该模块负责分析用户输入，判断用户意图，并调用相应的工具函数：
1. 当用户查询助手列表时，调用list_assistant工具
2. 当用户指定助手回答问题时，调用choose_assistant工具
3. 当用户直接提问时，调用auto_assistant_answer工具自动选择助手
"""
import json
import logging
import os
import time
from typing import Tuple, Optional

from dotenv import load_dotenv

# 导入工具函数
from RAGFlow_mcp.tool import list_assistant, choose_assistant, auto_assistant_answer, call_llm

# 获取项目根目录的绝对路径
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOGS_DIR = os.path.join(PROJECT_ROOT, 'logs')

# 确保日志目录存在
os.makedirs(LOGS_DIR, exist_ok=True)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(os.path.join(LOGS_DIR, 'ragflow_mcp_handler.log'), mode='a'),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger(__name__)
logger.info("RAGFlow MCP处理器模块初始化")

# 加载环境变量
load_dotenv()


# user_query: 用户问题
def analyze_user_intent(user_query) -> Tuple[str, Optional[str], Optional[str]]:
    """
    分析用户意图，判断用户是想查询助手列表、指定助手回答问题，还是直接提问
    :param user_query: 用户输入的查询
    :return:
        Tuple[str, Optional[str], Optional[str]]:
            - 意图类型: "list_assistant", "choose_assistant", "auto_assistant_answer"
            - 助手名称: 如果指定了助手，则返回助手名称，否则为None
            - 问题: 如果有问题，则返回问题内容，否则为None
    """
    logger.info(f"分析用户意图: '{user_query[:50]}...'")
    # 开始计算时间，后续会在日志中统计这一步花费的时间，便于勘误
    start_time = time.time()
    # 构建系统提示词
    system_prompt = """你是一个用户意图分析器。你需要判断用户的输入属于以下哪种类型：
        1. 查询助手列表：用户想知道有哪些可用的助手
        2. 指定助手回答问题：用户明确指定了某个助手来回答问题
        3. 直接提问：用户直接提出了问题，没有指定助手

        对于第2种情况，你需要提取出用户指定的助手名称。

        请以JSON格式返回分析结果，包含以下字段：
        - intent_type: "list_assistant", "choose_assistant", "auto_assistant_answer" 之一
        - assistant_name: 如果指定了助手，则返回助手名称，否则为null

        只返回JSON格式的结果，不要包含任何其他解释或文本。"""
    try:
        result = call_llm(user_query, system_prompt)
        try:
            # 去掉空格
            result = result.strip()
            # 需要判断当前结果result 需要以 ```json 开头
            if result.startswith("```json"):
                # 切片：去掉 ```json
                result = result[7:]
                # 删除后三个 ```
                result = result[:-3]
                # 获取到最新数据
                result = result.strip()
            # 将result 变为 Python 对象
            data = json.loads(result)
            # 调用get() 函数获取到值
            intent_type = data.get("intent_type")
            # 获取助手名称
            assistant_name = data.get("assistant_name")
            # 获取结束时间
            end_time = time.time()
            logger.info(
                f"成功分析用户意图 - 类型: {intent_type}, 助手: {assistant_name}, 耗时: {end_time - start_time:.2f}秒")
            # 对于所有情况，问题都是原始查询
            return intent_type, assistant_name, user_query
        except json.JSONDecodeError as e:
            logger.error(f"解析JSON失败: {str(e)}")
            # 默认为直接提问
            return "auto_assistant_answer", None, user_query
    except Exception as e:
        logger.error(f"解析JSON失败: {str(e)}")
        # 默认为直接提问
        return "auto_assistant_answer", None, user_query


# 入参：助手名称 出参：助手名称
def find_best_matching_assistant(assistant_name: str) -> str:
    """
    从助手列表中找到与用户指定名称最匹配的助手
    :param assistant_name: 用户指定的助手名称
    :return: 最匹配的助手名称
    """
    logger.info(f"查找与 '{assistant_name}' 最匹配的助手")
    #  获取开始时间
    start_time = time.time()
    try:
        # 先获取到所有的助手列表
        assistants_info = list_assistant()
        # 如果查询失败
        if not assistants_info or "获取助手列表时出错" in assistants_info:
            logger.error(f"获取助手列表失败: {assistants_info}")
            # 如果获取失败，直接返回通用助手,用于处理无法识别的任务
            return "通用知识助手"

            # 检查助手列表是否为空
        if "助手名称" not in assistants_info:
            logger.warning("助手列表为空或格式不正确")
            return "通用知识助手"

        # 声明变量记录当前助手名称
        assistant_names = []
        # 使用sprit("\n") 进行分割获取到数据
        # for line in assistants_info.split("\n"):
        lines = assistants_info.split("\n")
        # 循环遍历
        for line in lines:
            if "助手名称：" in line:
                # 截取到助手名称
                name = line.split("助手名称：")[1].split("；")[0].strip()
                # 将助手名称添加到列表中
                assistant_names.append(name)
        # 循环遍历获取到最佳的助手名称：
        for name in assistant_names:
            if assistant_name in name or name in assistant_name:
                #  打印日志找到助手
                logger.info(f"找到精确匹配的助手: '{name}'")
                # 获取结束时间
                end_time = time.time()
                logger.info(f"找到最匹配的助手: '{name}', 耗时: {end_time - start_time:.2f}秒")
                # 返回的是匹配的助手名称
                return name

        # 如果没有精确匹配，使用LLM进行智能匹配
        system_prompt = """你是一个助手匹配器。根据用户提供的助手名称，从可用的助手列表中找出最匹配的那个。

            只返回最匹配的助手的完整名称，不要添加任何解释或额外文本。"""

        user_prompt = f"""用户提供的助手名称: {assistant_name}

            可用的助手列表: {', '.join(assistant_names)}

            请返回最匹配的助手名称:"""

        # 调用LLM进行匹配,获取到精准的助手名称
        matched_assistant = call_llm(user_prompt, system_prompt).strip()

        # 清理结果
        # 去除LLM返回的可能包含的中英冒号及之前的多余文本
        # 去除中英分号后的多余文本
        if "：" in matched_assistant:
            matched_assistant = matched_assistant.split("：")[1].strip()
        if ":" in matched_assistant:
            matched_assistant = matched_assistant.split(":")[1].strip()
        if "；" in matched_assistant:
            matched_assistant = matched_assistant.split("；")[0].strip()
        if ";" in matched_assistant:
            matched_assistant = matched_assistant.split(";")[0].strip()

        # 验证LLM返回的结果是否在列表中
        for name in assistant_names:
            if matched_assistant in name:
                logger.info(f"LLM匹配成功: '{name}'")
                end_time = time.time()
                logger.info(f"找到最匹配的助手: '{name}', 耗时: {end_time - start_time:.2f}秒")
                return name

        # 如果还是不匹配，使用通用知识助手
        matched_assistant = "通用知识助手"
        logger.warning(f"无法找到精确匹配，使用通用知识助手作为备选")

        end_time = time.time()
        logger.info(f"找到最匹配的助手: '{matched_assistant}', 耗时: {end_time - start_time:.2f}秒")
        return matched_assistant

    except Exception as e:
        logger.error(f"查找失败: {str(e)}")
        # 默认返回第一个助手
        return "通用知识助手"


def handle_user_query(user_query: str) -> str:
    """
    处理用户查询，分析意图并调用相应的工具函数
    :param user_query: 用户输入的查询
    :return: 处理结果
    """
    logger.info(f"处理用户查询: '{user_query[:50]}...'")
    start_time = time.time()
    try:
        # 调用大模型进行意图识别
        # 第一个参数就是用户意图；第二个参数是助手名称；第三个参数是问题
        intent_type, assistant_name, question = analyze_user_intent(user_query)
        # 会根据用户意图调用不同的函数
        if intent_type == "list_assistant":
            logger.info("用户意图为: 列出助手")
            return list_assistant()
        # 指定助手查询
        elif intent_type == "choose_assistant" and assistant_name:
            logger.info(f"用户意图为: 指定助手查询 {assistant_name}")
            # 获取最佳匹配助手
            matched_assistant = find_best_matching_assistant(assistant_name)
            logger.info(f"最佳匹配的助手: '{matched_assistant}'")
            # 调用指定助手回答问题
            try:
                result = choose_assistant(matched_assistant, question)
                # 返回结果
                if "出错" in result or "错误" in result or "不存在" in result:
                    logger.error(f"助手 '{matched_assistant}' 出错: {result}")
                    # 根据问题自动识别助手
                    result = auto_assistant_answer(user_query)
            except Exception as e:
                logger.error(f"使用指定助手回答失败: {str(e)}")
                # 如果指定助手回答失败，尝试自动选择助手
                logger.info("尝试自动选择助手回答问题")
                result = auto_assistant_answer(user_query)
        else:  # auto_assistant_answer
            logger.info(f"用户意图: 直接提问")
            result = auto_assistant_answer(user_query)

        #   获取结束时间
        end_time = time.time()
        logger.info(f"用户查询处理完成，结果长度: {len(result)}, 总耗时: {end_time - start_time:.2f}秒")
        return result
    except Exception as e:
        logger.error(f"处理用户查询时出错: {str(e)}", exc_info=True)
        return f"处理您的问题时出现错误: {str(e)}"



if __name__ == "__main__":
    # 添加项目根目录到Python路径
    import os
    import sys

    PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.insert(0, PROJECT_ROOT)

    # 重新导入，使用绝对路径
    # from RAGFlow_mcp.tool import list_assistant, choose_assistant, auto_assistant_answer, call_llm

    test_queries = [
        "有哪些助手可以使用？",
        "用文学知识助手告诉我百年孤独的主角是谁？",
        "空调的绝热工程怎么做？"
    ]

    print("RAGFlow MCP处理器测试")

    for i, query in enumerate(test_queries):
        print(f"\n测试 {i + 1}: '{query}'")
        result = handle_user_query(query)
        print(f"结果:\n{result}")
